package com.a01_2021.thousandstimes.general.service.impl;

import com.a01_2021.thousandstimes.exception.CustomException;
import com.a01_2021.thousandstimes.general.entity.*;
import com.a01_2021.thousandstimes.general.mapper.ExperienceDetailMapper;
import com.a01_2021.thousandstimes.general.service.*;
import com.a01_2021.thousandstimes.instance.entity.LearnToday;
import com.a01_2021.thousandstimes.instance.entity.Vote;
import com.a01_2021.thousandstimes.instance.entity.WorkLog;
import com.a01_2021.thousandstimes.instance.service.ICommunicationService;
import com.a01_2021.thousandstimes.instance.service.ILearnTodayService;
import com.a01_2021.thousandstimes.instance.service.IVoteService;
import com.a01_2021.thousandstimes.instance.service.IWorkLogService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author E1xP
 * @since 2021-03-27
 */
@Service
public class ExperienceDetailServiceImpl extends ServiceImpl<ExperienceDetailMapper, ExperienceDetail> implements IExperienceDetailService {

    @Resource
    ExperienceDetailMapper experienceDetailMapper;

    @Resource
    IVoteService voteService;

    @Resource
    ILearnTodayService learnTodayService;

    @Resource
    ExperienceService experienceService;

    @Resource
    ICommunicationService communicationService;

    @Resource
    ISchoolService schoolService;

    @Resource
    PersonnelInfomationService personnelInfomationService;

    @Resource
    SysUserService sysUserService;

    @Resource
    IAbilityModelService abilityModelService;

    @Value("${ability.learnTodayCountThreshold}")
    double learnTodayCountThreshold;//计算今日学最高统计上限

    @Value("${ability.communicationCountThreshold}")
    double communicationCountThreshold;//员工沟通数量最高统计上限

    @Value("${ability.experienceCountThreshold}")
    double experienceCountThreshold;//员工经历数量最高统计上限

    @Autowired
    private EnglishComputerService englishComputerService;
    @Autowired
    private CredentialService credentialService;

    @Resource
    IWorkLogService workLogService;


    /**
     * 尝试评价（当且互评完成、hr评价完成时评价)
     *
     * @param userId 用户id
     * @param date   评价对应时间区间
     */
    @Override
    public void tryEvaluate(Long userId, LocalDate date) throws CustomException {
        if (this.canEvaluate(userId, date)) {
            this.doEvaluate(userId, date);
        }
    }


    /**
     * 用于执行评价
     *
     * @param userId 用户id
     * @param date   评价月时间
     */
    public void doEvaluate(long userId, LocalDate date) throws CustomException {
        //评价学习能力
        evalStudy(userId, date);
        //评价专业知识
        evalExperienced(userId, date);
        //评价人际交往能力
        evalInterpersonal(userId, date);
        //HR评价已经评价
        //该函数应当放在最后执行-用于评估员工竞争能力与总分统计
        this.tryEvalCompetition(date);
    }

    /**
     * 用于检查是否数据齐全
     *
     * @param userId 用户id
     * @param date   评价月时间
     * @return 是否数据齐全
     */
    public boolean canEvaluate(long userId, LocalDate date) {
        return isHrVote(userId, date) && voteService.isVoteEnough(userId, date);
    }

    /**
     * 用于检查HR是否对用户评分
     *
     * @param userId 用户id
     * @param date   评价月时间
     * @return HR是否评分
     */
    public boolean isHrVote(long userId, LocalDate date) {
        QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        //查询起止时间
        LocalDate startTime = date.minusDays(date.getDayOfMonth() - 1);
        LocalDate endTime = startTime.plusMonths(1);
        queryWrapper.eq("ability_id", AbilityEnum.COMPREHENSIVE_EVALUATION.getNo());
        queryWrapper.between("'time'", startTime, endTime);
        int count = experienceDetailMapper.selectCount(queryWrapper);
        return count > 0;
    }

    /**
     * 用于评价用户学习能力
     *
     * @param userId 用户id
     * @param date   评价对应时间
     * @throws CustomException 当用户不存在、无有效经历时抛出该异常
     */
    public void evalStudy(long userId, LocalDate date) throws CustomException {
        List<LearnToday> learnTodayList = learnTodayService.getFromUserIdAndDate(userId, date);
        int count = 0;
        for (LearnToday item : learnTodayList) {
            count += item.getContent().split("[。,\n]").length;//统计逗号与句号以及换行数量
        }
        double score = (count * 2.0 / learnTodayCountThreshold) % 2.0;
        long experienceId = experienceService.getCurrentExperienceId(userId, date);//获取当前有效经历id
        ExperienceDetail experienceDetail = new ExperienceDetail(null, userId, experienceId, AbilityEnum.STUDY_ABILITY.getNo(), score, date);
        experienceDetailMapper.insert(experienceDetail);
    }

    /**
     * 用于评价用户人际交往能力
     *
     * @param userId 用户id
     * @param date   评价对应时间
     * @throws CustomException 当用户不存在，无有效经历时抛出该异常
     */
    public void evalInterpersonal(long userId, LocalDate date) throws CustomException {
        int communicationCount = communicationService.getCommunicationCount(userId, date);//获取用户消息统计
        List<Vote> voteList = voteService.getVote(userId, date);
        //统计评分总分
        double sum = 0.0;
        for (Vote item : voteList) {
            sum += item.getScore();
        }
        double interpersonalScore = (sum / voteList.size() * 0.5 + communicationCount / communicationCountThreshold * 0.5) * 0.4 + 60;
        ExperienceDetail experienceDetail = new ExperienceDetail();
        //设置当前条目对应数据
        experienceDetail.setExperienceId(experienceService.getCurrentExperienceId(userId, date));
        experienceDetail.setScore(interpersonalScore);
        experienceDetail.setTime(date);
        experienceDetail.setUserId(userId);
        experienceDetail.setAbilityId(AbilityEnum.INTERPERSONAL_ABILITY.getNo());
        //插入数据库
        experienceDetailMapper.insert(experienceDetail);
    }

    /**
     * 用于评价用户英语和计算机水平
     *
     * @param userId 用户id
     * @param date   评价对应时间
     */
    public void englishComputer(Long userId, LocalDate date) throws CustomException {
        EnglishComputer englishComputer = englishComputerService.selectByUserId(userId);
        Credential credential1 = credentialService.getCredentialById(englishComputer.getEnglishId());
        Credential credential2 = credentialService.getCredentialById(englishComputer.getComputerId());
        //此处采取
        Double vote1 = (credential1.getMark()+credential2.getMark())*0.5+60;
        ExperienceDetail experienceDetail = new ExperienceDetail();
        //设置当前条目对应数据
        experienceDetail.setExperienceId(experienceService.getCurrentExperienceId(userId, date));
        experienceDetail.setScore(vote1);
        experienceDetail.setTime(date);
        experienceDetail.setUserId(userId);
        experienceDetail.setAbilityId(AbilityEnum.FOREIGN_LANGUAGE_AND_COMPUTER_ABILITY.getNo());
        //插入数据库
        experienceDetailMapper.insert(experienceDetail);
    }

    /**
     * 用于评价计划和执行能力
     *
     * @param userId 用户id
     * @param date   评价时间
     */

    @Override
    @DS("#header.instanceid")
    public void planExecute(Long userId, LocalDate date) throws CustomException {
        int complete = 0;
        List<WorkLog> workLogs = workLogService.getAllWorkLog(userId);
        for (WorkLog workLog : workLogs) {
            if(workLog.getComplete()==true){
                complete++;
            }
        }
        double score = (double) complete/workLogs.size() * 100;
        ExperienceDetail experienceDetail = new ExperienceDetail();
        //设置当前条目对应数据
        experienceDetail.setExperienceId(experienceService.getCurrentExperienceId(userId, date));
        experienceDetail.setScore(score);
        experienceDetail.setTime(date);
        experienceDetail.setUserId(userId);
        experienceDetail.setAbilityId(AbilityEnum.PLAN_EXECUTE_ABILITY.getNo());
        //插入数据库
        experienceDetailMapper.insert(experienceDetail);
    }

    /**
     * 用于评价用户专业知识评价
     *
     * @param userId 用户id
     * @param date   评价时间
     */
    public void evalExperienced(long userId, LocalDate date) throws CustomException {
        //获取对应个人信息
        PersonnelInfomation personnelInfomation = personnelInfomationService.getById(userId);
        double schoolScore = schoolService.getAvgScore(personnelInfomation.getName(), personnelInfomation.getBirthday());//获取其过去成绩均分
        int experienceCount = experienceService.getCount(userId);//用户经历统计
        double pastExperienceScore = experienceCount / experienceCountThreshold * 40 + 60;//计算员工分数
        //计算总分
        double experienceScore = schoolScore * 0.5 + pastExperienceScore * 0.5;
        //构建详情实体
        ExperienceDetail experienceDetail = new ExperienceDetail(null,
                userId,
                experienceService.getCurrentExperienceId(userId, date),
                AbilityEnum.PROFESSIONAL_ABILITY.getNo(),
                experienceScore,
                date);
        experienceDetailMapper.insert(experienceDetail);
    }

    /**
     * 用于统计用户的竞争能力与总分
     *
     * @param date 评价时间缩在月
     * @throws CustomException 不应当抛出该异常
     */
    public void evalCompetition(LocalDate date) throws CustomException {
        List<SysUser> sysUserList = sysUserService.getAllUser(1);
        List<ExperienceDetail> experienceDetailAll = new ArrayList<>();//用户总分存储
        HashMap<Long, AbilityModel> abilityModelHashMap = new HashMap<>();//用户对应评价模型
        //对所有人的7项评分进行加权计算后
        for (SysUser item : sysUserList) {
            List<ExperienceDetail> experienceDetailList = this.getFromUserId(item.getId(), date);
            AbilityModel abilityModel = abilityModelService.getByUserId(item.getId());
            abilityModelHashMap.put(item.getId(), abilityModel);//将用户评价模型放入map中
            double sumScore = 0.0;//剩余7项加权总分
            for (ExperienceDetail experienceDetail : experienceDetailList) {
                switch (experienceDetail.getAbilityId()) {
                    case 1:
                        sumScore += abilityModel.getAbility1Weight() * experienceDetail.getScore();
                        break;
                    case 2:
                        sumScore += abilityModel.getAbility2Weight() * experienceDetail.getScore();
                        break;
                    case 3:
                        sumScore += abilityModel.getAbility3Weight() * experienceDetail.getScore();
                        break;
                    case 4:
                        sumScore += abilityModel.getAbility4Weight() * experienceDetail.getScore();
                        break;
                    case 5:
                        sumScore += abilityModel.getAbility5Weight() * experienceDetail.getScore();
                        break;
                    case 7:
                        sumScore += abilityModel.getAbility7Weight() * experienceDetail.getScore();
                        break;
                    case 8:
                        sumScore += abilityModel.getAbility8Weight() * experienceDetail.getScore();
                        break;
                }
            }
            //将剩余7项评分压入链表中
            experienceDetailAll.add(new ExperienceDetail(null,
                    item.getId(),
                    experienceService.getCurrentExperienceId(item.getId(), date)
                    , AbilityEnum.OVER_ALL_SCORE.getNo(), sumScore, date));
        }
        //排序用户总分
        experienceDetailAll.sort((o1, o2) -> (int) (o1.getScore() - o2.getScore()));
        for (int i = 0; i < experienceDetailAll.size(); i++) {
            double score = 60 + 0.4 * i / experienceDetailAll.size();
            //将对应竞争得分加入数据库中
            ExperienceDetail experienceDetail = new ExperienceDetail(null,
                    experienceDetailAll.get(i).getUserId(),
                    experienceDetailAll.get(i).getExperienceId(),
                    AbilityEnum.COMPREHENSIVE_EVALUATION.getNo(),
                    score, date);
            experienceDetailMapper.insert(experienceDetail);
            //将竞争分加入总分中
            experienceDetailAll.get(i).setScore(experienceDetailAll.get(i).getScore() +
                    score * abilityModelHashMap.get(experienceDetailAll.get(i).getUserId()).getAbility6Weight());
        }
        //将总分插入数据库
        for (ExperienceDetail item : experienceDetailAll) {
            experienceDetailMapper.insert(item);
        }
    }

    /**
     * 用于尝试评价竞争能力
     *
     * @param date 评价时间
     */
    public void tryEvalCompetition(LocalDate date) throws CustomException {
        if (this.isAllBeEval(date)) {
            this.evalCompetition(date);
        }
    }

    /**
     * 用于判断是否其他已评价完
     *
     * @param date 评价时间
     * @return 返还是否其他项已评价完
     */
    public boolean isAllBeEval(LocalDate date) {
        QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
        LocalDate startDate = date.minusDays(date.getDayOfMonth() - 1);//查询开始时间
        LocalDate endDate = startDate.plusMonths(1);
        queryWrapper.between("time", startDate, endDate);
        int evalCount = experienceDetailMapper.selectCount(queryWrapper);
        int evalPersonCount = sysUserService.getUserCount(1);
        return evalCount >= evalPersonCount * 7;
    }

    /**
     * 用于获取用户在某月时的评分
     *
     * @param userId 用户id
     * @param date   查询评价所在月时间
     * @return 返还该用户的评价集合
     */
    public List<ExperienceDetail> getFromUserId(long userId, LocalDate date) {
        QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        LocalDate startDate = date.minusDays(date.getDayOfMonth() - 1);
        LocalDate endDate = startDate.plusMonths(1);
        queryWrapper.between("time", startDate, endDate);
        return experienceDetailMapper.selectList(queryWrapper);
    }

    /**
     * 用于获取用户的经历对应详细经历
     *
     * @param experienceId 经历id
     * @return Map
     */
    @Override
    public Map<String, Object> getExperienceDetail(long experienceId) {
        //查询经历所对应时间,总分
        List<LocalDate> dateList = experienceDetailMapper.getDate(experienceId);
        List<Double> scoreList = experienceDetailMapper.getOverAllScore(experienceId);
        //查询时间对应详细经历
        ArrayList<Map<Integer, Double>> arrayList = new ArrayList<>();
        for (LocalDate date : dateList) {
            //查询时间对应的8项评分
            QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("experience_id", experienceId).eq("time", date).ne("ability_id", AbilityEnum.OVER_ALL_SCORE.getNo());
            List<ExperienceDetail> experienceDetailList = experienceDetailMapper.selectList(queryWrapper);
            //将其以能力id-得分的形式封装
            Map<Integer, Double> abilityScoreMap = experienceDetailList.stream().collect(Collectors.toMap(ExperienceDetail::getAbilityId, ExperienceDetail::getScore));
            arrayList.add(abilityScoreMap);
        }
        //构造返回体
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("date", dateList);
        resultMap.put("score", scoreList);
        resultMap.put("detailScore", arrayList);
        return resultMap;
    }

    /**
     * 获取用户指定经历id的平均分
     *
     * @param experienceId 经历id
     * @return 返还指定经历id的平均分
     */
    @Override
    public double getAvgScore(Long experienceId) {
        QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("experience_id", experienceId).eq("ability_id", 9);
        List<ExperienceDetail> experienceDetailList = experienceDetailMapper.selectList(queryWrapper);
        double sum = 0.0;
        for (ExperienceDetail item : experienceDetailList) {
            sum += item.getScore();
        }
        return sum / experienceDetailList.size();
    }

    /**
     * 通过用户id与实例id获取用户经历详情
     *
     * @param userId     用户id
     * @param instanceId 实例id
     * @return List用户经历详情
     */
    @Override
    public List<ExperienceDetail> getFromInstanceIdAndUserId(Long userId, long instanceId) {
        QueryWrapper<ExperienceDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).eq("instance_id", instanceId);
        return experienceDetailMapper.selectList(queryWrapper);
    }

    /**
     * 将经历id获取
     *
     * @param experienceDetailList 经历详情列表
     * @param map                  旧-新经历id映射表
     */
    @DS("master")
    @Override
    public void insertIntoMaster(List<ExperienceDetail> experienceDetailList, Map<Long, Long> map) {
        for (ExperienceDetail item : experienceDetailList) {
            //映射旧经历id到新经历id
            item.setExperienceId(map.get(item.getExperienceId()));
        }
        experienceDetailMapper.insertList(experienceDetailList);
    }
}
